package ae.pcfc.etks.online.itworx.ehs.web.web.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import ae.pcfc.etks.online.itworx.ehs.web.common.exception.helper.ExceptionHandlerHelper;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.EHSDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.FNPDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.entity.DocumentType;
import ae.pcfc.etks.online.itworx.ehs.web.exception.CommunicationException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.DocumentTypeAlraedyExistException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.DocumentTypeNotFoundException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.FNPServiceExpcetion;
import ae.pcfc.etks.online.itworx.ehs.web.exception.InvalidDocumentTypeNameException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.InvalidInputException;
import ae.pcfc.etks.online.itworx.ehs.web.model.FNP;
import ae.pcfc.etks.online.itworx.ehs.web.model.FNPFeesParameter;
import ae.pcfc.etks.online.itworx.ehs.web.model.FNPFeesService;
import ae.pcfc.etks.online.itworx.ehs.web.util.MarshallingUtility;

@Controller
@RequestMapping("/admin")
@SessionAttributes("fnpAllServices")
public class Admin {

	private FNPDelegate fnpDelegate;
	private EHSDelegate ehsDelegate;
	private Logger log = LoggerFactory.getLogger(Admin.class);

	@Resource(name = "ehsDelegate")
	public void setEhsDelegate(EHSDelegate ehsDelegate) {
		this.ehsDelegate = ehsDelegate;
	}

	@Resource(name = "fnpDelegate")
	public void setFnpDelegate(FNPDelegate fnpDelegate) {
		this.fnpDelegate = fnpDelegate;
	}

	@RequestMapping(value = "/fnpMapping.htm", method = RequestMethod.GET)
	public String setupAdminForm(@ModelAttribute(value = "fnp") FNP fnp,
			Errors errors, Model model, Locale locale,
			HttpServletRequest request) {

		List<FNPFeesService> fnpAllServices = new ArrayList<FNPFeesService>();
		fnp = unmarshallFNP();
		try {
			fnpAllServices = fnpDelegate.getServices();

		} catch (CommunicationException commExp) {
			log.error(
					"Admin.setupAdminForm() - error happned while connecting to fnp to get services",
					commExp);
			ExceptionHandlerHelper.handleException(commExp);
			errors.reject(commExp.getErrorCode());
		}

		catch (FNPServiceExpcetion fnpExp) {
			log.error(
					"Admin.setupAdminForm() - FNP error happned while executing fnp to get services",
					fnpExp);
			ExceptionHandlerHelper.handleException(fnpExp);
			errors.reject(fnpExp.getErrorCode());
		} catch (Exception exp) {
			log.error("FNPInteraction.setupFNPForm() -  error", exp);
			errors.reject("error.generic");
		}
		model.addAttribute("fnp", fnp);
		model.addAttribute("fnpAllServices", fnpAllServices);
		if (locale.getLanguage().equals("ar")) {
			String queryString = request.getQueryString();
			String url = "redirect:fnpMapping.htm?lang=en";
			if (null != queryString && !queryString.isEmpty()) {
				url = url.concat("&" + queryString);
				return url;
			} else {
				return url;
			}
		}
		return "admin.fnpMapping";
	}

	@InitBinder
	protected void initBinder(HttpServletRequest request,
			ServletRequestDataBinder binder) throws Exception {
		binder.registerCustomEditor(List.class, "fnpServices",
				new CustomCollectionEditor(List.class) {
					protected Object convertElement(Object element) {
						if (element instanceof FNPFeesService) {
							return element;
						} else if (element instanceof String) {
							FNPFeesService service = new FNPFeesService();
							service.setServiceId(element.toString());
							return service;
						}
						return null;
					}
				});
	}

	@RequestMapping(value = "/fnpMapping.htm", method = RequestMethod.POST)
	public String queryForServiceParameters(Model model,
			@ModelAttribute(value = "fnp") FNP fnpModel, BindingResult errors,
			HttpServletRequest request) {
		try {
			List<FNPFeesService> fnpServices = null;
			if (null != fnpModel.getFnpServices()
					&& !fnpModel.getFnpServices().isEmpty()) {

				fnpServices = fnpDelegate.getServiceInfoAndParameters(fnpModel
						.getServicesId());
			}
			if (null != fnpServices) {

				Map<String, FNPFeesService> mappedList = fnpModel.listToMap();

				for (FNPFeesService service : fnpServices) {
					FNPFeesService fnpService = mappedList.get(service
							.getServiceId());
					fnpService.getFnpParameters().addAll(
							mapParameters(service.getServiceId(),
									service.getFnpParameters()));
				}
			}
			model.addAttribute("fnp", fnpModel);
		} catch (CommunicationException commExp) {
			log.error(
					"Admin.queryForServiceParameters() - error happned while connecting to fnp to get services info and parameters",
					commExp);
			ExceptionHandlerHelper.handleException(commExp);
			errors.reject(commExp.getErrorCode());
		} catch (FNPServiceExpcetion fnpExp) {
			log.error(
					"Admin.queryForServiceParameters() - FNP error happned while executing get services info and parameters",
					fnpExp);
			ExceptionHandlerHelper.handleException(fnpExp);
			errors.reject(fnpExp.getErrorCode());
		} catch (Exception exp) {
			log.error("FNPInteraction.setupFNPForm() -  error", exp);
			errors.reject("error.generic");
		}
		return "admin.fnpMapping";
	}

	private List<FNPFeesParameter> mapParameters(String serviceId,
			List<FNPFeesParameter> rawParameters) {
		FNP mappedFNP = unmarshallFNP();
		FNPFeesService service = mappedFNP.listToMap().get(serviceId);

		if (null != service) {
			for (FNPFeesParameter rawParameter : rawParameters) {
				FNPFeesParameter mappedParam = service.getParameterMap().get(
						rawParameter.getName());
				if (null != mappedParam) {
					rawParameter.setArabicName(mappedParam.getArabicName());
					rawParameter.setEnglishName(mappedParam.getEnglishName());
					rawParameter.setFormMappingField(mappedParam
							.getFormMappingField());
				}
			}
		}

		return rawParameters;
	}

	private FNP unmarshallFNP() {
		FNP fnp = null;
		try {
			fnp = MarshallingUtility.unmarshallFNP();
		} catch (Exception exp) {
			log.error(
					"Admin.unmarshallFNP() - error happned while un marshaling fnp",
					exp);
		}
		if (null == fnp) {
			fnp = new FNP();
		}
		return fnp;
	}

	@RequestMapping(value = "/thankyou.htm", method = RequestMethod.POST)
	public String marshallFNP(Model model,
			@ModelAttribute(value = "fnp") FNP fnpModel) {

		try {
			MarshallingUtility.marshallFNP(fnpModel);
		} catch (Exception exp) {
			log.error(
					"Admin.unmarshallFNP() - error happned while marshaling fnp",
					exp);
		}
		return "admin.thankyou";
	}

	private List<DocumentType> getDocumentTypesList() {
		List<DocumentType> documentTypeList = new ArrayList<DocumentType>();
		documentTypeList = ehsDelegate.getAllDocumentType();

		return documentTypeList;
	}

	@Transactional(readOnly = true)
	@RequestMapping(value = "/manageDocument.htm", method = RequestMethod.GET)
	public String manageDocumentType(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type, Locale locale)/*
																	 * ,
																	 * 
																	 * @RequestParam
																	 * (value =
																	 * "docTypeId"
																	 * ,
																	 * required
																	 * = false)
																	 * String
																	 * docTypeId
																	 * )
																	 */{

		List<DocumentType> documentTypeList = getDocumentTypesList();
		model.addAttribute("documentTypeList", documentTypeList);
		// System.out.println("delete STtaus: " +
		// (String)request.getAttribute("deleteStatus"));
		if (null != request.getAttribute("deleteStatus")) {
			// request.setAttribute("deleted", request.getParameter("deleted"));
			// messages.reject((String)request.getAttribute("deletedStatus"));
			request.setAttribute("deletedStatus",
					(String) request.getAttribute("deleteStatus"));
		}
		if (locale.getLanguage().equals("ar")) {
			String queryString = request.getQueryString();
			String url = "redirect:manageDocument.htm?lang=en";
			if (null != queryString && !queryString.isEmpty()) {
				url = url.concat("&" + queryString);
				return url;
			} else {
				return url;
			}
		}

		return "admin.manageDocument";

	}

	@Transactional
	@RequestMapping(value = "/editDocument.htm", method = RequestMethod.GET)
	public String editDocumentType(
			Model model,
			HttpServletRequest request,
			@RequestParam(value = "docTypeId", required = true) String docTypeId,
			@RequestParam(value = "type") String type, Locale locale) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */

		DocumentType documentTypeItem = null;
		try {
			Long docId = Long.valueOf(docTypeId);
			documentTypeItem = ehsDelegate.getDocumentTypeById(docId);
		} catch (DocumentTypeNotFoundException e) {
			log.error(
					"Admin.editDocumentType() - document not found for docTypeId("
							+ docTypeId + ")", e);
		} catch (InvalidInputException e) {
			log.error("Admin.editDocumentType() - invalid input docTypeId("
					+ docTypeId
					+ ") provided for ehsDelegate.getDocumentTypeById method",
					e);
		} catch (NumberFormatException e) {
			log.error(
					"Admin.editDocumentType() - number cannot be parsed for docTypeId("
							+ docTypeId + ")", e);
		}
		model.addAttribute("documentTypeItem", documentTypeItem);
		if (locale.getLanguage().equals("ar")) {
			String queryString = request.getQueryString();
			String url = "redirect:editDocument.htm?lang=en";
			if (null != queryString && !queryString.isEmpty()) {
				url = url.concat("&" + queryString);
				return url;
			}else{
				return url;
			}
		}
		return "admin.editDocument";// new
									// ModelMap("documentTypeList",documentTypeList);

	}

	@Transactional
	@RequestMapping(value = "/newDocument.htm", method = RequestMethod.GET)
	public String newDocumentType(Model model, HttpServletRequest request,
			Locale locale) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */

		// DocumentType documentTypeItem = null;
		// try {
		// Long docId = Long.valueOf(docTypeId);
		// documentTypeItem = ehsDelegate.getDocumentTypeById(docId);
		// } catch (DocumentTypeNotFoundException e) {
		// TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (InvalidInputException e) {
		// TODO Auto-generated catch block
		// e.printStackTrace();
		// }catch(NumberFormatException e){
		// e.printStackTrace();
		// }
		// model.addAttribute("documentTypeList", documentTypeList);

		// model.addAttribute("documentTypeItem",documentTypeItem);
		DocumentType documentTypeItem = new DocumentType();
		model.addAttribute("documentTypeItem", documentTypeItem);
		if (locale.getLanguage().equals("ar")) {
			String queryString = request.getQueryString();
			String url = "redirect:newDocument.htm?lang=en";
			if (null != queryString && !queryString.isEmpty()) {
				url = url.concat("&" + queryString);
				return url;
			}else{
				return url;
			}
		}
		return "admin.newDocument";// new
									// ModelMap("documentTypeList",documentTypeList);

	}

	@Transactional
	@RequestMapping(value = "/newDocument.htm", method = RequestMethod.POST)
	public String newDocumentType(
			@RequestParam(value = "type") String type,
			@ModelAttribute(value = "documentTypeItem") DocumentType documentTypeItem,
			BindingResult errors, Model model, HttpServletRequest request) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */
		// DocumentType documentTypeItem = null;
		errors = validateDocumentType(documentTypeItem, errors);
		if (errors.hasErrors()) {
			return "admin.newDocument";
		} else {

			try {
				ehsDelegate.createNewDocumentType(documentTypeItem);
			} catch (InvalidDocumentTypeNameException e) {
				log.error(
						"Admin.newDocumentType() - invalid document name while creating new documentType ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.createUpdateType");
				return "admin.newDocument";
			} catch (DocumentTypeAlraedyExistException e) {
				log.error(
						"Admin.newDocumentType() - document is already exist error while creating new documentType ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.createUpdateType");
				return "admin.newDocument";
			} catch (InvalidInputException e) {
				log.error(
						"Admin.newDocumentType() - invalid input provided while creating new documentType ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.documentTypeInvalid");
				return "admin.newDocument";
			} catch (RuntimeException e) {
				log.error(
						"Admin.newDocumentType() - RuntimeException excption while creating new documentType ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.runtime");
				return "admin.newDocument";
			}
			// model.addAttribute("documentTypeList", documentTypeList);
			// model.addAttribute("documentTypeItem",documentTypeItem);
			// return "redirect:/admin/manageDocument.htm?type="+type;// new
			// ModelMap("documentTypeList",documentTypeList);
			request.setAttribute("created", "true");
			return "admin.newDocument";
		}

	}

	@Transactional(readOnly = true)
	@RequestMapping(value = "/deleteDocument.htm", method = RequestMethod.GET)
	public String deleteDocumentType(
			Model model,
			@RequestParam(value = "docTypeId", required = true) String docTypeId,
			@RequestParam(value = "type") String type,
			HttpServletRequest request, Locale locale) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */
		DocumentType documentTypeItem = null;
		try {
			Long docId = Long.valueOf(docTypeId);
			documentTypeItem = ehsDelegate.getDocumentTypeById(docId);
		} catch (DocumentTypeNotFoundException e) {
			log.error(
					"Admin.deleteDocumentType() - document not found for documentTypeId("
							+ docTypeId + ")", e);
		} catch (InvalidInputException e) {
			log.error(
					"Admin.deleteDocumentType() - invalid input provided while getting document type documentTypeId("
							+ docTypeId + ")", e);
		} catch (NumberFormatException e) {
			log.error(
					"Admin.deleteDocumentType() - number form,at exception while parsing documentTypeId("
							+ docTypeId + ")", e);
		}

		model.addAttribute("documentTypeItem", documentTypeItem);
		// return "admin.editDocument";
		if (locale.getLanguage().equals("ar")) {
			String queryString = request.getQueryString();
			String url = "redirect:deleteDocument.htm?lang=en";
			if (null != queryString && !queryString.isEmpty()) {
				url = url.concat("&" + queryString);
				return url;
			}else{
				return url;
			}
		}
		return "admin.deleteDocument";// "redirect:/admin/manageDocument.htm?type=manageDocument";//
										// new
										// ModelMap("documentTypeList",documentTypeList);

	}

	@Transactional
	@RequestMapping(value = "/deleteDocument.htm", method = RequestMethod.POST)
	public String deleteDocumentType(
			Model model,
			@ModelAttribute(value = "documentTypeItem") DocumentType documentTypeItem,
			BindingResult errors, @RequestParam(value = "type") String type,
			HttpServletRequest request) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */
		// String deleteStatus = "error.admin.documentTypeNotDeleted";
		if (null == documentTypeItem || documentTypeItem.getId() == 0) {
			errors.reject("error.admin.documentTypeInvalid");
			return "admin.deleteDocument";
		}

		try {
			// Long docId = Long.valueOf(docTypeId);

			ehsDelegate.deleteDocumentType(documentTypeItem.getId());
			// errors.reject("message.admin.documentTypeDeleted");
		} catch (DocumentTypeNotFoundException e) {
			log.error(
					"Admin.deleteDocumentType() -  document not found for documentTypeId("
							+ documentTypeItem.getId() + ")", e);
			errors.reject("error.admin.documentTypeInvalid");
		} catch (InvalidInputException e) {
			log.error(
					"Admin.deleteDocumentType() -  invalid input provided while getting document type documentTypeId("
							+ documentTypeItem.getId() + ")", e);
			errors.reject("error.admin.documentTypeInvalid");
		}
		// model.addAttribute("documentTypeList", documentTypeList);
		// model.addAttribute("documentTypeItem",documentTypeItem);
		request.setAttribute("deleteStatus", "true");
		return "admin.deleteDocument";// "redirect:/admin/manageDocument.htm?type=manageDocument";//
										// new
										// ModelMap("documentTypeList",documentTypeList);

	}

	@Transactional
	@RequestMapping(value = "/editDocument.htm", method = RequestMethod.POST)
	public String editDocumentType(
			@RequestParam(value = "type") String type,
			@ModelAttribute(value = "documentTypeItem") DocumentType documentTypeItem,
			BindingResult errors, Model model, HttpServletRequest request) {
		/*
		 * ,
		 * 
		 * @RequestParam(value = "type",required = true) String type,
		 * 
		 * @RequestParam(value = "docTypeId", required = false) String docTypeId
		 */
		// DocumentType documentTypeItem = null;
		errors = validateDocumentType(documentTypeItem, errors);
		if (errors.hasErrors()) {
			return "admin.editDocument";
		} else {

			try {
				ehsDelegate.updateDocumentType(documentTypeItem);
			} catch (InvalidDocumentTypeNameException e) {
				// errors.addError(new ObjectError(""));
				// String[] errArgs = new String[1];
				log.error(
						"Admin.editDocumentType() -  invalid document type name provided ("
								+ documentTypeItem.getEnglishName() + ")", e);
				errors.reject("error.admin.createUpdateType");
				return "admin.editDocument";
			} catch (DocumentTypeNotFoundException e) {
				log.error(
						"Admin.editDocumentType() -  document type not found for ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.documentTypeInvalid");
				return "admin.editDocument";
			} catch (InvalidInputException e) {
				log.error(
						"Admin.editDocumentType() -  invalid input provided while updating document type ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.documentTypeInvalid");
				return "admin.editDocument";
			} catch (DocumentTypeAlraedyExistException e) {
				log.error(
						"Admin.editDocumentType() -  document type is already exist in DB for document type ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.createUpdateType");
				return "admin.editDocument";
			} catch (RuntimeException e) {
				log.error(
						"Admin.editDocumentType() -  run time exception occurred while editing document type ("
								+ documentTypeItem + ")", e);
				errors.reject("error.admin.runtime");
				return "admin.editDocument";
			}
			// model.addAttribute("documentTypeList", documentTypeList);
			// model.addAttribute("documentTypeItem",documentTypeItem);
			// return "redirect:/admin/manageDocument.htm?type="+type;// new
			// ModelMap("documentTypeList",documentTypeList);
			request.setAttribute("updated", "true");
			return "admin.editDocument";
		}

	}

	private BindingResult validateDocumentType(DocumentType documentTypeItem,
			BindingResult errors) {

		if (null == documentTypeItem.getEnglishName()
				|| documentTypeItem.getEnglishName().trim().equals("")
				|| documentTypeItem.getEnglishName().length() > 50) {
			errors.reject("error.admin.englishTitle");
		}
		if (null == documentTypeItem.getArabicName()
				|| documentTypeItem.getArabicName().trim().equals("")
				|| documentTypeItem.getArabicName().length() > 50) {
			errors.reject("error.admin.arabicTitle");
		}

		return errors;
	}

}
